#include "strategies/SimEVDiscardStrategy.h"
#include "Query.h"
#include <cstdlib>
#include <vector>

using namespace std;

int SimEVDiscardStrategy::pickDiscard (CCardStack* hand, bool lastPicked, const GameState* gameState) {
    // Get the possible values from the different possible discards
    vector<int> ownCardValues = Query::FourCardValues(*hand);
    int handRange = lastPicked ? 3 : 4;  // Ignore the last card if necessary
    if (handRange == 3) {
        ownCardValues.pop_back();
    }
    int toDiscard = Query::maxValueIndex(ownCardValues);
    // Get known opponent hand and find how many unknown cards and possible combinations to fill those cards
    int opponent = (gameState->getCurrPlayer() + 1) % 2;
    CCardStack oppHand = gameState->getCardsPickedUpAndHeldByPlayer(opponent);
    int unknownCards = 3 - oppHand.Size();  
    if (unknownCards == 3) {
        decisionCertainty = 0;
    }
    else if (unknownCards > 0) {
        // Must simulate
        CCardStack possibleCards = gameState->getUnknownCards(gameState->getCurrPlayer());
        int maxCombinations = Query::choose(possibleCards.Size(), unknownCards);
        // Calculate the number of simulations from the given parameter;
        int numSimulations = simulationRange * maxCombinations / 100;
        // Simulate opponent hands and find best EV from value differences
        int bestEV = 0;
        CCardStack auxStack;
        for (int i = 0; i < numSimulations; i++) {
            if (possibleCards.Size() < unknownCards) {
                possibleCards.Push(auxStack);
                auxStack.Clear();
            }
            for (int j = 0; j < unknownCards; j++) {
                const CCard& card = possibleCards.RemoveCard(Query::RandomChoice(possibleCards.Size()));
                oppHand.Push(CCard(card.GetIndex()));
            }
            for (int j = 0; j < handRange; j++) {
                int ev = ownCardValues.at(j) - Query::maxGainFromCard(oppHand, hand->at(j));
                if (ev > bestEV) {
                    bestEV = ev;
                    toDiscard = j;
                }
            }
            auxStack.Push(oppHand.Pop(unknownCards));
        }
        decisionCertainty = simulationRange;    // The agent is as sure as the fraction of possible hands simulated (which will be an overestimation because of possible repetitions in the sampling)
    }
    else {
        int bestEV = 0;
        for (int i = 0; i < handRange; i++) {
            int ev = ownCardValues.at(i) - Query::maxGainFromCard(oppHand, hand->at(i));
            if (ev > bestEV) {
                bestEV = ev;
                toDiscard = i;
            }
        }
        decisionCertainty = 100;
    }
    return toDiscard;
}
